<html>
<head><meta charset="utf-8"><title>Converting `&amp;AtomicFoo` to `&amp;[AtomicU8; N]` and using it · t-lang/wg-unsafe-code-guidelines · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/index.html">t-lang/wg-unsafe-code-guidelines</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html">Converting `&amp;AtomicFoo` to `&amp;[AtomicU8; N]` and using it</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="224880394"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224880394" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thom Chiovoloni <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224880394">(Feb 02 2021 at 14:46)</a>:</h4>
<p>Is it legal to convert <code>&amp;Atomic$Int</code> to an appropriately sized <code>&amp;[AtomicU8; N]</code> and do operations on it while other threads continue to work on the full-sized object? Or more broadly, can I do this sort of "manually tearing" of atomic operations?</p>
<p>Specifically, I have an <code>AtomicU32</code>, and I would like to do a CAS on (only) the least significant byte while other threads will be reading and/or writing the whole <code>AtomicU32</code>.</p>
<p>I would have assumed this is fine, and it's very hard for me to imagine it not working in practice (hardware certainly allows it... as if that matters), but someone planted some doubt in my mind that perhaps this is actually UB.</p>
<p>I don't <em>think</em> this is a kind of data race (the accesses <em>are</em> synchronized), but on the other hand, I know certain data race detectors like loom (and relacy) would complain about this, but I believe that's limitations of their impl rather than something fundamental (for example: AtomicU8 isn't just 1 byte in either loom or relacy I believe — although I think it is for CDSChecker).</p>
<p>Note: I also know that in C++ this is totally unsupported because strict aliasing applies to <code>atomic&lt;uint8_t&gt;</code> (and probably <code>_Atomic uint8_t</code> for C), so I worry that the existing C++ memory model work wouldn't be much help here...</p>



<a name="224903730"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224903730" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Josh Triplett <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224903730">(Feb 02 2021 at 17:15)</a>:</h4>
<p>I don't know that doing that is defined behavior of atomics. If it works on all current hardware, we could perhaps define it as such.</p>



<a name="224904969"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224904969" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> bjorn3 <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224904969">(Feb 02 2021 at 17:22)</a>:</h4>
<p>What if you use different orderings on different parts of the full atomic? What would the ordering be relative to the full atomic?</p>



<a name="224907078"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224907078" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224907078">(Feb 02 2021 at 17:36)</a>:</h4>
<p>Given the fact we cannot rely on C++ to say whether or not this is allowed, due to strict aliasing, I assume the question would become, does llvm allow this? If llvm does not, that would probably answer the question for rust, at least for the llvm backend of rustc.</p>



<a name="224917822"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224917822" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224917822">(Feb 02 2021 at 18:50)</a>:</h4>
<p>From a theoretical POV I don't see any reason to disallow this. If you use different orderings on non-overlapping parts of an atomic, it's just as if you had multiple atomics; for overlapping atomic operations they would be ordered the same as if they were on one atomic, at least wrt reads of the overlap. If you read an atomic using multiple atomic operations of the subparts then of course that's not atomic. Is there an edge case I'm forgetting?</p>



<a name="224918241"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224918241" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224918241">(Feb 02 2021 at 18:53)</a>:</h4>
<p>Does C++ let you do <code>atomic&lt;atomic&lt;uint8_t&gt;[8]&gt;</code>?</p>



<a name="224918427"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224918427" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Mario Carneiro <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224918427">(Feb 02 2021 at 18:54)</a>:</h4>
<p>That doesn't have arbitrary overlapping but it does have nested atomic operations</p>



<a name="224918436"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224918436" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224918436">(Feb 02 2021 at 18:54)</a>:</h4>
<p>No, because atomic&lt;T&gt; mandates T be <em>trivially copyable</em> and it's not copyable at all (copy and move constructors and assignments are deleted, for the same reason it's not Copy or Clone in rust)</p>



<a name="224953068"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224953068" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thom Chiovoloni <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224953068">(Feb 02 2021 at 23:36)</a>:</h4>
<p><span class="user-mention silent" data-user-id="257758">Connor Horman</span> <a href="#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it/near/224907078">said</a>:</p>
<blockquote>
<p>Given the fact we cannot rely on C++ to say whether or not this is allowed, due to strict aliasing, I assume the question would become, does llvm allow this? If llvm does not, that would probably answer the question for rust, at least for the llvm backend of rustc.</p>
</blockquote>
<p>In practice LLVM has some stuff like <code>memcpy.element.unordered.atomic</code> intrinsics (<a href="https://llvm.org/docs/LangRef.html#llvm-memcpy-element-unordered-atomic-intrinsic">https://llvm.org/docs/LangRef.html#llvm-memcpy-element-unordered-atomic-intrinsic</a>) which notes that:</p>
<blockquote>
<p>the copy between buffers uses a sequence of unordered atomic load/store operations that are a positive integer multiple of the element_size in size.</p>
</blockquote>
<p>Given that it's a multiple of the element size (e.g. <em>not</em> identical to the element size), this <em>seems</em> to imply to me that this is fine for LLVM, at least for unordered.</p>
<p>(That said, the orderings I care about are relaxed/acquire/release and not unordered, so that doesn't answer anything conclusively)</p>



<a name="224956107"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224956107" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thom Chiovoloni <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224956107">(Feb 03 2021 at 00:09)</a>:</h4>
<p>That said, it does note about the unordered memcpy ops that:</p>
<blockquote>
<p>It is well defined to have concurrent reads and writes to both source and destination provided those reads and writes are unordered atomic when specified.</p>
</blockquote>
<p>Which is surprising. My perhaps-overly-optimistic hunch is that this is just because it was all that was needed for e.g. Java, and they didn't want to specify more than was needed.</p>
<blockquote>
<p>Given the fact we cannot rely on C++ to say whether or not this is allowed, due to strict aliasing</p>
</blockquote>
<p>While looking into this I found this <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1478r6.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1478r6.html</a>, which seems to be progressing pretty well and has a lot of interesting/related discussion.</p>
<hr>
<p>Note: For clarity, the use case I'm interested in (that I made the thread for) is not atomic memcpy, it's in implementing a waiter set for a mutex+condvar. I'm mostly mentioning them since ISTM like if atomic memcpy is well defined here, then what I'm asking would also be well defined.</p>



<a name="224957218"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/224957218" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Connor Horman <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#224957218">(Feb 03 2021 at 00:21)</a>:</h4>
<p>Actually, now that I think about it,  C++20 has <code>std::atomic_ref</code> (and it's actually mentioned in that paper), so you could do this, by taking an atomic_ref to a <code>std::byte</code> (which is exempted from strict aliasing). I'd be interested in knowing whether this currently does valid things (devles right into <a href="https://eel.is/c++draft">https://eel.is/c++draft</a>).</p>



<a name="225415875"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/225415875" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#225415875">(Feb 06 2021 at 15:05)</a>:</h4>
<p>this is called "mixed-size accesses" in the academic literature, and is notoriously difficult to specify precisely (like, even harder than "normal" weak-memory concurrency^^). but other than that I don't think there's any reason it should be disallowed.</p>



<a name="225415892"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/225415892" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#225415892">(Feb 06 2021 at 15:05)</a>:</h4>
<p>also see <a href="https://www.cl.cam.ac.uk/~pes20/popl17/mixed-size.pdf">https://www.cl.cam.ac.uk/~pes20/popl17/mixed-size.pdf</a></p>



<a name="225421212"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/225421212" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Thom Chiovoloni <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#225421212">(Feb 06 2021 at 17:17)</a>:</h4>
<blockquote>
<p>is notoriously difficult to specify precisely</p>
</blockquote>
<p>Ah, that explains why it seemed like everything that touches on it is (such as the C++) deliberately going out of its way to avoid talking about the case I'm interested in</p>
<blockquote>
<p>also see <a href="https://www.cl.cam.ac.uk/~pes20/popl17/mixed-size.pdf">https://www.cl.cam.ac.uk/~pes20/popl17/mixed-size.pdf</a></p>
</blockquote>
<p>That's a very good and interesting paper, thanks. There are some limitations around SeqCst that they discuss, but personally that doesn't sound too unreasonable for me.</p>
<p>These sorts of accesses are very rare, and are likely to be only used by code that's actively tuning the algorithm, which means it's unlikely to want to be using SeqCst in the first place. (but this may be my personal bias, as IMO algorithms that require SeqCst are too hard to reason about — better to use things that can be expressed with acquire release semantics than to worry about interleavings)</p>
<p>Also, it indicated that this issue already exists for PPC regardless of mixed access, apparently.</p>



<a name="225459133"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting%20%60%26AtomicFoo%60%20to%20%60%26%5BAtomicU8%3B%20N%5D%60%20and%20using%20it/near/225459133" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> RalfJ <a href="https://rust-lang.github.io/zulip_archive/stream/136281-t-lang/wg-unsafe-code-guidelines/topic/Converting.20.60.26AtomicFoo.60.20to.20.60.26.5BAtomicU8.3B.20N.5D.60.20and.20using.20it.html#225459133">(Feb 07 2021 at 11:20)</a>:</h4>
<blockquote>
<p>Also, it indicated that this issue already exists for PPC regardless of mixed access, apparently.</p>
</blockquote>
<p>Yeah, turns out specifying SeqCst is really hard when you start mixing SeqCst and other accesses on the same location. C++11 had a bug there; C++2x will fix that. see <a href="https://plv.mpi-sws.org/scfix/">https://plv.mpi-sws.org/scfix/</a> .<br>
This problem is AFAIK not closely related to mixed-size accesses though (but I am out of the loop on the details here).</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>